package iot_aliyun

import (
	"encoding/json"
	"fmt"
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"github.com/shopspring/decimal"
	"strconv"
	"time"
)

// IDataSpec 数据类型:
//
//	int（原生）、
//	float（原生）、
//	double（原生）、
//	text（原生）、
//	date（String类型UTC毫秒）、
//	bool（0或1的int类型）、
//	enum（枚举项定义方法与bool类型定义0和1的值方法相同）、
//	struct（结构体类型，可包含前面7种类型，下面使用 "specs":[{}]描述包含的对象）、
//	array（数组类型，支持int、double、float、text、struct）
type IDataSpec interface {
	TypeName() string
	Copy() IDataSpec

	MockData() interface{} //模拟数据用
}

var DataSpecList = []IDataSpec{
	&IntData{},
	&FloatData{},
	&DoubleData{},
	&TextData{},
	&EnumData{},
	&BoolData{},
	&ArrayData{},
	&StructData{},
}

type FloatData struct {
	Min      string `json:"min"`      //参数最小值（int、float、double类型特有）
	Max      string `json:"max"`      //参数最大值（int、float、double类型特有）
	Step     string `json:"step"`     //步长（int、float、double类型特有）
	Unit     string `json:"unit"`     //属性单位（int、float、double类型特有，非必填）,如 %
	UnitName string `json:"unitName"` //单位名称（int、float、double类型特有，非必填）,如 百分比
}

func (d FloatData) TypeName() string {
	return "int"
}

func (d FloatData) Copy() IDataSpec {
	return &FloatData{}
}
func (d FloatData) MockData() interface{} {
	mi, _ := strconv.ParseFloat(d.Min, 64)
	ma, _ := strconv.ParseFloat(d.Max, 64)
	step, _ := strconv.ParseFloat(d.Step, 64)
	if step == 0 {
		step = 0.1
	}
	if ma <= mi {
		ma = mi + 1
	}
	l := (ma - mi) / step

	return mi + float64(utils.TrueScopeRand(0, int64(l)))*step
}

type IntData struct {
	Min      string `json:"min"`      //参数最小值（int、float、double类型特有）
	Max      string `json:"max"`      //参数最大值（int、float、double类型特有）
	Step     string `json:"step"`     //步长（int、float、double类型特有）
	Unit     string `json:"unit"`     //属性单位（int、float、double类型特有，非必填）,如 %
	UnitName string `json:"unitName"` //单位名称（int、float、double类型特有，非必填）,如 百分比
}

func (d IntData) TypeName() string {
	return "float"
}
func (d IntData) Copy() IDataSpec {
	return &IntData{}
}
func (d IntData) MockData() interface{} {
	mi, _ := strconv.ParseFloat(d.Min, 64)
	ma, _ := strconv.ParseFloat(d.Max, 64)
	if ma <= mi {
		ma = mi + 10
	}

	return utils.TrueScopeRand(int64(mi), int64(ma))
}

type DoubleData struct {
	Min      string `json:"min"`      //参数最小值（int、float、double类型特有）
	Max      string `json:"max"`      //参数最大值（int、float、double类型特有）
	Step     string `json:"step"`     //步长（int、float、double类型特有）
	Unit     string `json:"unit"`     //属性单位（int、float、double类型特有，非必填）,如 %
	UnitName string `json:"unitName"` //单位名称（int、float、double类型特有，非必填）,如 百分比
}

func (d DoubleData) TypeName() string {
	return "double"
}
func (d DoubleData) Copy() IDataSpec {
	return &DoubleData{}
}
func (d DoubleData) MockData() interface{} {
	mi, _ := strconv.ParseFloat(d.Min, 64)
	ma, _ := strconv.ParseFloat(d.Max, 64)
	step, _ := strconv.ParseFloat(d.Step, 64)
	if step == 0 {
		step = 0.1
	}
	if ma <= mi {
		ma = mi + 10
	}
	l := (ma - mi) / step

	//if l > 10 {
	//	l = float64(utils.TrueScopeRand(1, 10))
	//}

	//return mi + float64(utils.TrueScopeRand(0, int64(l)))*step //有精度问题

	f, _ := decimal.NewFromInt(utils.TrueScopeRand(0, int64(l))).Mul(decimal.NewFromFloat(step)).Add(decimal.NewFromFloat(mi)).Float64()
	return f

}

type TextData struct {
	Length string `json:"length"`
}

func (d TextData) TypeName() string {
	return "text"
}
func (d TextData) Copy() IDataSpec {
	return &TextData{}
}
func (d TextData) MockData() interface{} {
	return utils.RandLetterFigureCode(10)
}

// DateData date（String类型UTC毫秒）
type DateData struct {
}

func (d DateData) TypeName() string {
	return "date"
}
func (d DateData) Copy() IDataSpec {
	return &DateData{}
}
func (d DateData) MockData() interface{} {
	return fmt.Sprint(time.Now().UnixMilli())
}

// BoolData （0或1的int类型）、
type BoolData map[string]string //key=0对应false，key=1对应true
// 示例： {"type":"enum","specs":"{\"0\":\"enum1\",\"1\":\"enum2\"}"}

func (d BoolData) TypeName() string {
	return "bool"
}
func (d BoolData) Copy() IDataSpec {
	return &BoolData{}
}
func (d BoolData) MockData() interface{} {
	i := int64(0)
	r := utils.TrueScopeRand(0, int64(len(d))-1)
	for _, v := range d {
		if r == i {
			return v
		}
		i++
	}
	return ""
}

// EnumData enum（枚举项定义方法与bool类型定义0和1的值方法相同）
// 示例： {"type":"enum","specs":"{\"1\":\"enum1\",\"2\":\"enum2\",\"3\":\"enum3\"}"}
type EnumData map[string]string

func (d EnumData) TypeName() string {
	return "enum"
}
func (d EnumData) Copy() IDataSpec {
	return &EnumData{}
}
func (d EnumData) MockData() interface{} {
	i := int64(0)
	r := utils.TrueScopeRand(0, int64(len(d)))
	for _, v := range d {
		if r == i {
			return v
		}
		i++
	}
	return ""
}

// StructData （结构体类型，可包含前面7种类型，下面使用 "specs":[{}]描述包含的对象）、
type StructData []StructDataItem

type StructDataItem struct {
	Identifier string        `json:"identifier"` // 参数唯一标识符
	Name       string        `json:"name"`       // 参数名称
	DataType   ThingDataType `json:"dataType"`   // 参数的数据类型
}

func (d StructData) TypeName() string {
	return "struct"
}
func (d StructData) Copy() IDataSpec {
	return &StructData{}
}
func (d StructData) String() string {
	s, _ := json.Marshal(d)
	return string(s)
}
func (d StructData) MockData() interface{} {
	var m = map[string]interface{}{}
	for _, v := range d {
		m[v.Identifier] = v.DataType.Specs.MockData()
	}

	return m
}

// ArrayData （数组类型，支持int、double、float、text、struct）
type ArrayData struct {
	Size string        `json:"size"`
	Item ThingDataType `json:"item"`
}

func (d ArrayData) TypeName() string {
	return "array"
}
func (d ArrayData) Copy() IDataSpec {
	return &ArrayData{}
}
func (d ArrayData) String() string {
	s, _ := json.Marshal(d)
	return string(s)
}
func (d ArrayData) MockData() interface{} {
	var arr []interface{}
	size, _ := strconv.Atoi(d.Size)
	if size > 10 {
		size = int(utils.TrueScopeRand(1, 10))
	}
	for i := 1; i <= size; i++ {
		arr = append(arr, d.Item.Specs.MockData())
	}
	return arr
}

func ConvertThingDataType(data IDataSpec) ThingDataType {
	return ThingDataType{
		Type:  data.TypeName(),
		Specs: data,
	}
}
